﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Bluetooth.Rfcomm;
using Windows.Devices.Enumeration;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace SplitViewOptions.Bluetooth
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class Beaconpage : Page
    {
        public Beaconpage()
        {
            this.InitializeComponent();
            watcher.Received += Watcher_Received;
            Loaded += Beaconpage_Loaded;
            watcher.Start();
            Listen();
        }

        private void Beaconpage_Loaded(object sender, RoutedEventArgs e)
        {
            connect();
        }

        private async void Watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
        {

            MessageDialog one = new MessageDialog("Watcher_Received");
            await one.ShowAsync();
            // We can obtain various information about the advertisement we just received by accessing 
            // the properties of the EventArgs class

            // The timestamp of the event
            DateTimeOffset timestamp = eventArgs.Timestamp;

            // The type of advertisement
            BluetoothLEAdvertisementType advertisementType = eventArgs.AdvertisementType;

            // The received signal strength indicator (RSSI)
            Int16 rssi = eventArgs.RawSignalStrengthInDBm;

            // The local name of the advertising device contained within the payload, if any
            string localName = eventArgs.Advertisement.LocalName;

            // Check if there are any manufacturer-specific sections.
            // If there is, print the raw data of the first manufacturer section (if there are multiple).
            string manufacturerDataString = "";
            var manufacturerSections = eventArgs.Advertisement.ManufacturerData;
            if (manufacturerSections.Count > 0)
            {
                // Only print the first one of the list
                var manufacturerData = manufacturerSections[0];
                var data = new byte[manufacturerData.Data.Length];
                using (var reader = DataReader.FromBuffer(manufacturerData.Data))
                {
                    reader.ReadBytes(data);
                }
                // Print the company ID + the raw data in hex format
                manufacturerDataString = string.Format("0x{0}: {1}",
                    manufacturerData.CompanyId.ToString("X"),
                    BitConverter.ToString(data));
            }

            // Serialize UI update to the main UI thread
            await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                // Display these information on the list
                ReceivedAdvertisementListBox.Items.Add(string.Format("[{0}]: type={1}, rssi={2}, name={3}, manufacturerData=[{4}]",
                    timestamp.ToString("hh\\:mm\\:ss\\.fff"),
                    advertisementType.ToString(),
                    rssi.ToString(),
                    localName,
                    manufacturerDataString));
            });
        }

        BluetoothLEAdvertisementWatcher watcher = new BluetoothLEAdvertisementWatcher();
        private StreamSocket _socket;
        private DeviceInformation device;
        private RfcommDeviceService _service;

        private async void connect()
        {
            try
            {
                var devices =
                      await DeviceInformation.FindAllAsync(
                        RfcommDeviceService.GetDeviceSelector(
                          RfcommServiceId.SerialPort));

                //  device = devices.Single(x => x.Name == "HC-05");
                device = devices.First();
                _service = await RfcommDeviceService.FromIdAsync(device.Id);
                 _socket = new StreamSocket();
                await _socket.ConnectAsync(
                      _service.ConnectionHostName,
                      _service.ConnectionServiceName,
                      SocketProtectionLevel.
                      BluetoothEncryptionAllowNullAuthentication);
                 Send("duocao");
            }
            catch (Exception ex)
            {
                MessageDialog one = new MessageDialog("error ");
                await one.ShowAsync();
            }
        }
        private async void btnDisconnect_Click(object sender,RoutedEventArgs e)
        {
          //  tbError.Text = string.Empty;

            try
            {
                await _socket.CancelIOAsync();
                _socket.Dispose();
                _socket = null;
                _service.Dispose();
                _service = null;
            }
            catch (Exception ex)
            {
               // tbError.Text = ex.Message;
            }
        }
        private async void Listen()
        {
            ReadCancellationTokenSource = new CancellationTokenSource();
            if (_socket.InputStream != null)
            {
                dataReaderObject = new DataReader(_socket.InputStream);
                // keep reading the serial input
                while (true)
                {
                    await ReadAsync(ReadCancellationTokenSource.Token);
                }
            }
        }
        private async void Send(string msg)
        {
            Task<UInt32> storeAsyncTask;

            DataWriter dataWriteObject = new DataWriter(_socket.OutputStream);
            dataWriteObject.WriteString(msg);

            // Launch an async task to complete the write operation
            storeAsyncTask = dataWriteObject.StoreAsync().AsTask();

            UInt32 bytesWritten = await storeAsyncTask;
        }
        DataReader dataReaderObject;
        private CancellationTokenSource ReadCancellationTokenSource;
        private Task<uint> loadAsyncTask;

        private async Task ReadAsync(CancellationToken cancellationToken)
        {
            uint ReadBufferLength = 1024;

            // If task cancellation was requested, comply
            cancellationToken.ThrowIfCancellationRequested();

            // Set InputStreamOptions to complete the asynchronous read operation when one or more bytes is available
            dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;

            // Create a task object to wait for data on the serialPort.InputStream
            loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(cancellationToken);

            // Launch the task and wait
            UInt32 bytesRead = await loadAsyncTask;
            if (bytesRead > 0)
            {
                string recvdtxt = dataReaderObject.ReadString(bytesRead);
              await  App.showmessage(recvdtxt);
                //MessageDialog one = new MessageDialog(recvdtxt);
                //await one.ShowAsync();
            }
        }
    }
}
